import streamlit as st
import requests
import json
import time
from datetime import datetime
import os
import threading
import traceback
from typing import List, Dict, Any, Iterator

# 简化的导入，只保留必要的组件
from langchain_core.callbacks import BaseCallbackHandler

# 设置页面配置
st.set_page_config(
    page_title="LangChain智能聊天机器人",
    page_icon="🤖",
    layout="wide"
)

# 自定义CSS样式
st.markdown("""
<style>
    @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
    
    :root {
        --primary-color: #4a6fa5;
        --secondary-color: #6c757d;
        --success-color: #28a745;
        --warning-color: #ffc107;
        --danger-color: #dc3545;
        --light-color: #f8f9fa;
        --dark-color: #343a40;
        --background-color: #f0f2f6;
        --chat-bg-color: #ffffff;
        --user-bg-color: #e3f2fd;
        --bot-bg-color: #f5f5f5;
    }
    
    body {
        font-family: 'Inter', sans-serif;
        background-color: var(--background-color);
    }
    
    .main-container {
        max-width: 900px;
        margin: 0 auto;
        padding: 1rem;
    }
    
    .header {
        text-align: center;
        padding: 1.5rem 0;
        margin-bottom: 2rem;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        border-radius: 12px;
        color: white;
        box-shadow: 0 8px 20px rgba(0,0,0,0.1);
    }
    
    .header h1 {
        font-size: 2.2rem;
        font-weight: 700;
        margin-bottom: 0.5rem;
    }
    
    .header p {
        font-size: 1rem;
        opacity: 0.95;
        margin-bottom: 0;
    }
    
    .api-key-container {
        background-color: var(--light-color);
        padding: 1.5rem;
        border-radius: 10px;
        margin-bottom: 2rem;
        border: 1px solid #e0e0e0;
    }
    
    .api-key-container h3 {
        margin-top: 0;
        color: var(--dark-color);
        font-size: 1.2rem;
        margin-bottom: 1rem;
    }
    
    .api-link {
        color: var(--primary-color);
        text-decoration: none;
        font-weight: 600;
        transition: color 0.3s ease;
    }
    
    .api-link:hover {
        color: #3a5b8f;
        text-decoration: underline;
    }
    
    .chat-container {
        background-color: var(--chat-bg-color);
        border-radius: 12px;
        box-shadow: 0 4px 15px rgba(0,0,0,0.05);
        overflow: hidden;
        border: 1px solid #e0e0e0;
    }
    
    .chat-header {
        background-color: #f8f9fa;
        padding: 1rem 1.5rem;
        border-bottom: 1px solid #e0e0e0;
        display: flex;
        justify-content: space-between;
        align-items: center;
    }
    
    .chat-header h3 {
        margin: 0;
        color: var(--dark-color);
        font-size: 1.1rem;
    }
    
    .clear-btn {
        background-color: transparent;
        color: var(--secondary-color);
        border: 1px solid var(--secondary-color);
        padding: 0.4rem 0.8rem;
        border-radius: 6px;
        cursor: pointer;
        font-size: 0.9rem;
        transition: all 0.3s ease;
    }
    
    .clear-btn:hover {
        background-color: var(--secondary-color);
        color: white;
    }
    
    .chat-history {
        padding: 1.5rem;
        max-height: 500px;
        overflow-y: auto;
        scroll-behavior: smooth;
    }
    
    .message {
        margin-bottom: 1rem;
        animation: fadeIn 0.3s ease-in-out;
    }
    
    @keyframes fadeIn {
        from {
            opacity: 0;
            transform: translateY(10px);
        }
        to {
            opacity: 1;
            transform: translateY(0);
        }
    }
    
    .user-message {
        display: flex;
        justify-content: flex-end;
    }
    
    .bot-message {
        display: flex;
        justify-content: flex-start;
    }
    
    .message-content {
        max-width: 75%;
        padding: 0.8rem 1.2rem;
        border-radius: 18px;
        box-shadow: 0 2px 8px rgba(0,0,0,0.05);
        word-wrap: break-word;
    }
    
    .user-message .message-content {
        background-color: var(--user-bg-color);
        border-bottom-right-radius: 4px;
    }
    
    .bot-message .message-content {
        background-color: var(--bot-bg-color);
        border-bottom-left-radius: 4px;
    }
    
    .message-time {
        font-size: 0.75rem;
        color: var(--secondary-color);
        margin-top: 0.25rem;
        text-align: right;
    }
    
    .bot-message .message-time {
        text-align: left;
    }
    
    .input-container {
        padding: 1.5rem;
        background-color: var(--chat-bg-color);
        border-top: 1px solid #e0e0e0;
    }
    
    .input-field {
        width: 100%;
    }
    
    .stTextArea > div > div {
        border-radius: 8px;
        border: 1px solid #ddd;
        transition: all 0.3s ease;
    }
    
    .stTextArea > div > div:focus-within {
        border-color: var(--primary-color);
        box-shadow: 0 0 0 3px rgba(74, 111, 165, 0.1);
    }
    
    .send-btn {
        background-color: var(--primary-color);
        color: white;
        border: none;
        padding: 0.75rem 2rem;
        font-size: 1rem;
        font-weight: 600;
        border-radius: 8px;
        cursor: pointer;
        transition: all 0.3s ease;
        margin-top: 0.5rem;
        width: 100%;
    }
    
    .send-btn:hover {
        background-color: #3a5b8f;
        transform: translateY(-1px);
        box-shadow: 0 4px 12px rgba(74, 111, 165, 0.3);
    }
    
    .send-btn:disabled {
        background-color: #cccccc;
        cursor: not-allowed;
        transform: none;
        box-shadow: none;
    }
    
    .loading-indicator {
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 1rem;
    }
    
    .loading-spinner {
        border: 3px solid #f3f3f3;
        border-top: 3px solid var(--primary-color);
        border-radius: 50%;
        width: 20px;
        height: 20px;
        animation: spin 1s linear infinite;
        margin-right: 0.5rem;
    }
    
    @keyframes spin {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
    }
    
    .error-message {
        background-color: rgba(220, 53, 69, 0.1);
        color: var(--danger-color);
        padding: 1rem;
        border-radius: 8px;
        margin: 1rem 0;
        border-left: 4px solid var(--danger-color);
    }
    
    .success-message {
        background-color: rgba(40, 167, 69, 0.1);
        color: var(--success-color);
        padding: 1rem;
        border-radius: 8px;
        margin: 1rem 0;
        border-left: 4px solid var(--success-color);
    }
    
    .tip-box {
        background-color: rgba(255, 193, 7, 0.1);
        padding: 1rem;
        border-radius: 8px;
        border-left: 4px solid var(--warning-color);
        margin: 1rem 0;
    }
    
    .tip-box h4 {
        color: #856404;
        margin-top: 0;
        margin-bottom: 0.5rem;
    }
    
    .tip-box p {
        margin: 0;
        color: #856404;
        font-size: 0.9rem;
    }
    
    @media (max-width: 768px) {
        .message-content {
            max-width: 85%;
        }
    }
</style>
""", unsafe_allow_html=True)

# 初始化会话状态
if "messages" not in st.session_state:
    st.session_state.messages = []
    # 添加机器人的自我介绍
    st.session_state.messages.append({
        "role": "assistant",
        "content": "您好！我是您的智能助手，很高兴为您服务。我可以回答问题、提供信息或帮助您解决问题。请问有什么我可以帮助您的吗？",
        "timestamp": datetime.now().strftime("%H:%M")
    })

if "api_key" not in st.session_state:
    st.session_state.api_key = ""

if "loading" not in st.session_state:
    st.session_state.loading = False

if "error" not in st.session_state:
    st.session_state.error = None

if "recommended_questions" not in st.session_state:
    st.session_state.recommended_questions = []

if "selected_question" not in st.session_state:
    st.session_state.selected_question = ""

# 自定义处理类
class StreamHandler:
    def __init__(self, container, initial_text=""):
        self.container = container
        self.text = initial_text
        self.full_text = ""
        self.error = None
    
    def update_text(self, token: str) -> None:
        """更新文本内容"""
        try:
            self.text += token
            self.full_text += token
            if self.container:
                self.container.markdown(self.text)
            print(f"[调试] 收到新token: {token[:20]}...")
        except Exception as e:
            self.error = str(e)
            print(f"[错误] 更新UI失败: {str(e)}")

# 先定义所有需要的函数
def call_qwen_api_stream(prompt: str, api_key: str, max_tokens: int = 2000, temperature: float = 0.7) -> Iterator[str]:
    """
    流式调用通义千问API
    """
    url = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation"
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {api_key}"
    }
    
    data = {
        "model": "qwen-turbo",
        "input": {
            "messages": [
                {
                    "role": "user",
                    "content": prompt
                }
            ]
        },
        "parameters": {
            "temperature": temperature,
            "max_tokens": max_tokens,
            "stream": True
        }
    }
    
    try:
        print(f"[调试] 正在发送API请求到: {url}")
        print(f"[调试] 请求头: {headers.keys()}")  # 不打印完整headers以保护密钥
        print(f"[调试] 请求数据: 模型={data['model']}, stream={data['parameters']['stream']}")
        
        response = requests.post(url, headers=headers, json=data, stream=True, timeout=30)
        
        print(f"[调试] API响应状态码: {response.status_code}")
        print(f"[调试] API响应头: {response.headers}")
        
        response.raise_for_status()
        
        # 处理流式响应
        received_data = False
        chunks_received = False
        total_content = ""
        
        for line in response.iter_lines():
            if line:
                received_data = True
                line = line.decode('utf-8')
                print(f"[调试] 收到原始响应行: {line[:100]}..." if len(line) > 100 else f"[调试] 收到原始响应行: {line}")
                
                # 处理数据行
                if line.startswith('data: '):
                    line = line[6:]  # 去掉 'data: ' 前缀
                    if line.strip() == '[DONE]':
                        print("[调试] 收到结束标记[DONE]")
                        break
                
                try:
                    chunk = json.loads(line)
                    print(f"[调试] 解析出的JSON块: {chunk.keys()}")
                    
                    # 检查是否有错误信息
                    if 'error' in chunk:
                        print(f"[错误] API返回错误: {chunk['error']}")
                        raise Exception(f"API错误: {chunk['error'].get('message', '未知错误')}")
                    
                    # 检查output字段
                    if 'output' in chunk and isinstance(chunk['output'], dict):
                        # 提取text内容
                        if 'text' in chunk['output'] and chunk['output']['text']:
                            content = chunk['output']['text']
                            chunks_received = True
                            total_content += content
                            yield content
                            print(f"[调试] 成功提取内容片段: {content[:50]}...")
                        else:
                            print(f"[警告] output中没有text字段或text为空")
                    else:
                        print(f"[警告] 响应中没有output字段或output不是字典")
                        # 打印完整响应内容以便调试
                        print(f"[调试] 完整块内容: {str(chunk)}")
                except json.JSONDecodeError as e:
                    print(f"[错误] 解析JSON失败: {e}, 行内容: {line[:50]}...")
                    continue
        
        print(f"[调试] API调用完成，响应长度: {len(total_content)}字符")
        print(f"[调试] 是否收到数据: {received_data}, 是否收到内容块: {chunks_received}")
        
        # 检查是否收到任何内容
        if not received_data:
            print("[警告] 没有收到任何数据")
            # 如果没有收到数据，尝试读取完整响应
            full_response = response.text
            print(f"[调试] 完整响应内容: {full_response[:200]}..." if len(full_response) > 200 else f"[调试] 完整响应内容: {full_response}")
        elif not chunks_received:
            print("[错误] 收到了数据但未能正确解析出内容块")
            # 尝试读取完整响应进行调试
            full_response = response.text
            print(f"[调试] 完整响应内容: {full_response[:200]}..." if len(full_response) > 200 else f"[调试] 完整响应内容: {full_response}")
            raise Exception("API调用成功，但未能正确解析响应内容。可能是API响应格式不符合预期。")
        elif len(total_content) == 0:
            print("[错误] 解析出了内容块但内容为空")
            raise Exception("API调用成功，但返回的内容为空。可能是内容被过滤或生成失败。")
            
    except requests.exceptions.RequestException as e:
        print(f"[错误] HTTP请求异常: {str(e)}")
        # 尝试提供更具体的错误信息
        if hasattr(e, 'response') and e.response:
            print(f"[错误] 响应状态码: {e.response.status_code}")
            print(f"[错误] 响应内容: {e.response.text[:500]}..." if len(e.response.text) > 500 else f"[错误] 响应内容: {e.response.text}")
        raise
    except Exception as e:
        print(f"[错误] 通义千问API调用失败: {str(e)}")
        raise

def get_streaming_langchain_response(question: str, api_key: str, bot_message_id: int) -> str:
    """
    使用LangChain格式构建提示并调用通义千问API
    """
    try:
        # 验证API密钥格式
        if not api_key or not api_key.strip():
            raise ValueError("API密钥不能为空")
        
        print(f"[调试] 开始处理问题: {question}")
        print(f"[调试] API密钥长度: {len(api_key)}字符")
        
        # 构建LangChain风格的提示
        system_message = "你是一个有用的AI助手，回答问题要准确、友好。"
        
        # 添加历史消息
        history_text = ""
        for i, msg in enumerate(st.session_state.messages):
            if i != bot_message_id:  # 跳过正在生成的消息
                role = "用户" if msg["role"] == "user" else "助手"
                history_text += f"{role}: {msg['content']}\n\n"
        
        # 构建完整提示
        full_prompt = f"{system_message}\n\n{history_text}用户: {question}\n\n助手: "
        
        print(f"[调试] 提示构建完成，长度: {len(full_prompt)}字符")
        
        # 执行流式调用
        print("[调试] 开始调用通义千问API")
        
        # 处理流式响应
        full_response = ""
        chunks_received = False
        last_update_time = time.time()
        
        # 直接使用requests进行API调用，优化响应处理
        url = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation"
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {api_key}"
        }
        
        data = {
            "model": "qwen-turbo",
            "input": {
                "messages": [
                    {
                        "role": "user",
                        "content": full_prompt
                    }
                ]
            },
            "parameters": {
                "temperature": 0.7,
                "max_tokens": 2000,
                "stream": True
            }
        }
        
        print(f"[调试] 发送API请求，URL: {url}")
        
        try:
            response = requests.post(url, headers=headers, json=data, stream=True, timeout=30)
            response.raise_for_status()
            
            print(f"[调试] API响应状态码: {response.status_code}")
            
            # 处理流式响应
            for line in response.iter_lines():
                if line:
                    line = line.decode('utf-8')
                    print(f"[调试] 收到原始响应行: {line[:100]}..." if len(line) > 100 else f"[调试] 收到原始响应行: {line}")
                    
                    # 处理data前缀
                    if line.startswith('data: '):
                        line = line[6:]
                        if line.strip() == '[DONE]':
                            print("[调试] 收到结束标记[DONE]")
                            break
                    
                    # 尝试解析JSON
                    try:
                        chunk = json.loads(line)
                        
                        # 检查是否有错误
                        if 'error' in chunk:
                            error_msg = chunk['error'].get('message', 'API返回错误')
                            print(f"[错误] API返回错误: {error_msg}")
                            raise Exception(f"API错误: {error_msg}")
                        
                        # 提取内容
                        if 'output' in chunk and isinstance(chunk['output'], dict):
                            if 'text' in chunk['output'] and chunk['output']['text']:
                                content = chunk['output']['text']
                                chunks_received = True
                                full_response += content
                                print(f"[调试] 提取到内容: {content[:50]}...")
                                
                                # 更新会话状态中的消息内容
                                st.session_state.messages[bot_message_id]["content"] = full_response
                                
                                # 控制更新频率，避免过多的rerun
                                current_time = time.time()
                                if current_time - last_update_time >= 0.3 or len(content) > 100:  # 至少0.3秒或收到较多内容才更新
                                    st.rerun()
                                    last_update_time = current_time
                            else:
                                print("[警告] output中没有text字段或内容为空")
                        else:
                            print(f"[警告] 响应格式不符合预期，缺少output字段: {list(chunk.keys())}")
                            # 尝试从其他可能的字段提取内容
                            if 'text' in chunk:
                                print(f"[调试] 尝试从根级别text字段获取内容")
                                content = chunk['text']
                                chunks_received = True
                                full_response += content
                                st.session_state.messages[bot_message_id]["content"] = full_response
                                st.rerun()
                    except json.JSONDecodeError as e:
                        print(f"[警告] 解析JSON失败: {e}，跳过此行")
                        continue
        except Exception as inner_e:
            print(f"[错误] 处理API响应时发生错误: {str(inner_e)}")
            raise
        
        # 确保最后一次更新UI
        if full_response and last_update_time != time.time():
            st.rerun()
            
        print(f"[调试] API调用完成，响应长度: {len(full_response)}字符")
        
        # 检查是否收到了任何内容
        if not chunks_received:
            error_msg = "API调用成功，但未收到任何内容块。可能是响应格式问题。"
            print(f"[错误] {error_msg}")
            st.session_state.messages[bot_message_id]["content"] = f"⚠️ {error_msg}\n\n请检查：\n1. API密钥是否正确\n2. 网络连接是否正常\n3. API响应格式是否发生变化"
            st.rerun()
            return error_msg
        
        if len(full_response) == 0:
            error_msg = "API调用成功，但返回内容为空。可能是内容被过滤或生成失败。"
            print(f"[错误] {error_msg}")
            st.session_state.messages[bot_message_id]["content"] = f"⚠️ {error_msg}\n\n请检查：\n1. 您的提问是否合规\n2. 账号是否有足够额度\n3. 稍后再试"
            st.rerun()
            return error_msg
        
        return full_response
        
    except requests.exceptions.ConnectionError:
        error_msg = "网络连接失败，请检查您的网络连接。"
        print(f"[错误] {error_msg}")
        st.session_state.messages[bot_message_id]["content"] = f"⚠️ {error_msg}\n\n请检查：\n1. 网络连接是否正常\n2. 防火墙是否阻止了连接\n3. API服务是否可访问"
        st.rerun()
        return error_msg
        
    except requests.exceptions.Timeout:
        error_msg = "API调用超时，请稍后重试。"
        print(f"[错误] {error_msg}")
        st.session_state.messages[bot_message_id]["content"] = f"⚠️ {error_msg}\n\n请检查：\n1. 网络连接是否稳定\n2. 稍后再试"
        st.rerun()
        return error_msg
        
    except requests.exceptions.HTTPError as e:
        # 处理HTTP错误，提供更具体的信息
        status_code = e.response.status_code if hasattr(e, 'response') and e.response else "未知"
        error_msg = f"HTTP错误 (状态码: {status_code})："
        
        # 根据常见状态码提供更具体的建议
        if status_code == 401:
            error_msg += "未授权访问，API密钥可能无效。"
            suggestion = "请检查您的API密钥是否正确，以及是否已在阿里云平台激活。"
        elif status_code == 403:
            error_msg += "权限不足，可能是API密钥权限不够或额度已用完。"
            suggestion = "请检查您的API账号是否有足够权限，以及是否还有调用额度。"
        elif status_code == 429:
            error_msg += "请求过于频繁，请稍后再试。"
            suggestion = "请减少请求频率，稍后再试。"
        elif status_code == 500 or status_code == 502 or status_code == 503:
            error_msg += "服务器错误，请稍后再试。"
            suggestion = "这是服务器端的问题，请稍后再试。"
        else:
            error_msg += str(e)
            suggestion = "请检查API密钥和网络连接后重试。"
        
        print(f"[错误] {error_msg}")
        st.session_state.messages[bot_message_id]["content"] = f"⚠️ {error_msg}\n\n{suggestion}"
        st.rerun()
        return error_msg
        
    except Exception as e:
        error_msg = f"API调用失败: {str(e)}"
        print(f"[错误] {error_msg}")
        # 在UI上显示友好的错误信息
        st.session_state.messages[bot_message_id]["content"] = f"⚠️ 发生错误：{str(e)}\n\n请检查：\n1. API密钥是否正确\n2. 网络连接是否正常\n3. 通义千问API服务是否正常"
        st.rerun()
        return error_msg

def generate_recommended_questions(user_question: str, ai_response: str) -> List[str]:
    """
    生成推荐问题
    """
    try:
        if not st.session_state.api_key:
            return []
        
        # 构建提示
        prompt = f"""
基于以下对话内容，生成3个相关的后续问题，用于帮助用户继续与AI助手交流。

用户问题: {user_question}

AI回答: {ai_response}

请直接输出3个问题，每个问题占一行，不要添加任何额外的格式或编号。
        """
        
        # 调用通义千问API
        url = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation"
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {st.session_state.api_key}"
        }
        
        data = {
            "model": "qwen-turbo",
            "input": {
                "messages": [
                    {
                        "role": "user",
                        "content": prompt
                    }
                ]
            },
            "parameters": {
                "temperature": 0.7,
                "max_tokens": 1000,
                "stream": False
            }
        }
        
        response = requests.post(url, headers=headers, json=data, timeout=30)
        response.raise_for_status()
        result = response.json()
        
        # 处理响应
        if 'output' in result and 'text' in result['output']:
            content = result['output']['text']
            # 提取问题列表
            questions = [q.strip() for q in content.strip().split("\n") if q.strip()]
            
            # 如果生成的问题不足3个，添加默认问题
            if len(questions) < 3:
                default_questions = [
                    "关于这个话题，您还能提供更多细节吗？",
                    "这个信息对我很有用，您能再举个例子吗？",
                    "您能帮我总结一下关键点吗？"
                ]
                for q in default_questions:
                    if q not in questions:
                        questions.append(q)
                    if len(questions) >= 3:
                        break
            
            return questions[:3]  # 最多返回3个问题
        else:
            raise Exception("API返回格式错误")
        
    except Exception as e:
        print(f"[错误] 生成推荐问题失败: {str(e)}")
        # 返回默认推荐问题
        return [
            "您还想了解什么相关信息？",
            "您对这个回答满意吗？",
            "还有其他我可以帮助您的吗？"
        ]

def send_message():
    if not st.session_state.api_key.strip():
        st.session_state.error = "请先设置API密钥"
        return
    
    user_input = st.session_state.get("user_input", "").strip()
    if not user_input:
        st.session_state.error = "请输入消息内容"
        return
    
    # 清空之前的错误
    st.session_state.error = None
    
    # 添加用户消息到会话
    user_message = {
        "role": "user",
        "content": user_input,
        "timestamp": datetime.now().strftime("%H:%M")
    }
    st.session_state.messages.append(user_message)
    
    # 不直接修改session_state.user_input，而是让Streamlit在下一次渲染时自动处理输入框重置
    # 我们可以使用rerun来确保页面正确刷新
    pass
    
    # 设置加载状态
    st.session_state.loading = True
    
    try:
        # 创建一个空的AI回复占位符
        bot_message_id = len(st.session_state.messages)
        st.session_state.messages.append({
            "role": "assistant",
            "content": "",  # 初始为空，将通过LangChain更新
            "timestamp": datetime.now().strftime("%H:%M")
        })
        
        # 使用LangChain流式调用
        full_response = get_streaming_langchain_response(user_input, st.session_state.api_key, bot_message_id)
        
        # 生成新的推荐问题
        st.session_state.recommended_questions = generate_recommended_questions(user_input, full_response)
        
    except Exception as e:
        st.session_state.error = f"API调用失败: {str(e)}"
        # 移除占位符消息
        if len(st.session_state.messages) > 0 and st.session_state.messages[-1]["role"] == "assistant" and not st.session_state.messages[-1]["content"]:
            st.session_state.messages.pop()
    finally:
        # 重置加载状态
        st.session_state.loading = False

# 主容器
st.markdown('<div class="main-container">', unsafe_allow_html=True)

# 标题部分
st.markdown("""
<div class="header">
    <h1>🤖 LangChain智能聊天机器人</h1>
    <p>基于LangChain和通义千问API的智能对话助手</p>
</div>
""", unsafe_allow_html=True)

# 在侧边栏中添加API密钥设置
with st.sidebar:
    st.markdown("""
    <style>
        .sidebar-header {
            text-align: center;
            padding: 1rem 0;
            margin-bottom: 1rem;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            border-radius: 8px;
            color: white;
        }
        
        .sidebar-header h3 {
            margin: 0;
            font-size: 1.1rem;
        }
        
        .sidebar-section {
            background-color: #f8f9fa;
            padding: 1rem;
            border-radius: 8px;
            margin-bottom: 1rem;
            border: 1px solid #e0e0e0;
        }
        
        .sidebar-section h4 {
            margin-top: 0;
            margin-bottom: 0.75rem;
            color: #343a40;
            font-size: 1rem;
        }
        
        .sidebar-tip {
            background-color: rgba(255, 193, 7, 0.1);
            padding: 0.75rem;
            border-radius: 6px;
            margin-top: 0.75rem;
            font-size: 0.9rem;
        }
        
        .sidebar-tip h5 {
            margin: 0 0 0.5rem 0;
            color: #856404;
            font-size: 0.9rem;
        }
        
        .sidebar-tip p {
            margin: 0;
            color: #856404;
            font-size: 0.85rem;
        }
        
        .sidebar-link {
            color: #4a6fa5;
            text-decoration: none;
            font-weight: 500;
        }
        
        .sidebar-link:hover {
            text-decoration: underline;
        }
    </style>
    """, unsafe_allow_html=True)
    
    # 侧边栏标题
    st.markdown("""
    <div class="sidebar-header">
        <h3>🔑 API设置</h3>
    </div>
    """, unsafe_allow_html=True)
    
    # API密钥输入区域
    st.markdown('<div class="sidebar-section">', unsafe_allow_html=True)
    st.markdown('<h4>通义千问API密钥</h4>', unsafe_allow_html=True)
    
    # API密钥输入
    api_key = st.text_input(
        "",
        value=st.session_state.api_key,
        type="password",
        placeholder="请输入您的API密钥",
        label_visibility="collapsed",
        key="sidebar_api_key"
    )
    
    # 保存按钮
    save_button = st.button("保存密钥", use_container_width=True, key="sidebar_save_button")
    
    # 保存API密钥逻辑
    if save_button:
        if api_key.strip():
            st.session_state.api_key = api_key.strip()
            st.session_state.error = None
            st.sidebar.success("✅ API密钥已保存")
        else:
            st.sidebar.error("❌ 请输入有效的API密钥")
    
    # API密钥获取提示
    st.markdown("""
    <div class="sidebar-tip">
        <h5>💡 如何获取API密钥？</h5>
        <p>请访问 <a href="https://dashscope.console.aliyun.com/apiKey" class="sidebar-link" target="_blank">阿里云通义千问API</a> 注册并创建您的通义千问API密钥。</p>
    </div>
    """, unsafe_allow_html=True)
    st.markdown('</div>', unsafe_allow_html=True)
    
    # 额外功能区域
    st.markdown('<div class="sidebar-section">', unsafe_allow_html=True)
    st.markdown('<h4>🔧 功能选项</h4>', unsafe_allow_html=True)
    
    # 清除聊天记录按钮
    clear_chat_sidebar = st.button("清除聊天记录", use_container_width=True, key="sidebar_clear_chat")
    if clear_chat_sidebar:
        st.session_state.messages = []
        st.session_state.error = None
        st.sidebar.success("✅ 聊天记录已清除")
    
    # API密钥状态显示
    st.markdown("<div style='margin-top: 1rem; font-size: 0.85rem; color: #6c757d;'>", unsafe_allow_html=True)
    if st.session_state.api_key:
        st.markdown("**🔒 API密钥状态:** 已设置")
    else:
        st.markdown("**🔒 API密钥状态:** 未设置")
    st.markdown("</div>", unsafe_allow_html=True)
    st.markdown('</div>', unsafe_allow_html=True)
    
    # 页脚信息
    st.markdown("""
    <div style='margin-top: 2rem; text-align: center; font-size: 0.8rem; color: #6c757d;'>
        © 2024 LangChain智能聊天机器人<br>
        基于LangChain和通义千问API
    </div>
    """, unsafe_allow_html=True)

# 聊天界面
st.markdown('<div class="chat-container">', unsafe_allow_html=True)

# 聊天标题栏
st.markdown("""
<div class="chat-header">
    <h3>对话历史</h3>
</div>
""", unsafe_allow_html=True)

# 顶部提示信息
if not st.session_state.api_key:
    st.info("💡 请在左侧边栏设置您的通义千问API密钥以开始对话")

# 显示错误信息
if st.session_state.error:
    st.markdown(f"""
    <div class="error-message">
        <strong>❌ 错误:</strong> {st.session_state.error}
    </div>
    """, unsafe_allow_html=True)

# 聊天历史区域
st.markdown('<div class="chat-history">', unsafe_allow_html=True)

# 显示聊天记录
for message in st.session_state.messages:
    role = message["role"]
    content = message["content"]
    timestamp = message.get("timestamp", datetime.now().strftime("%H:%M"))
    
    if role == "user":
        st.markdown(f"""
        <div class="message user-message">
            <div class="message-content">
                {content}
                <div class="message-time">{timestamp}</div>
            </div>
        </div>
        """, unsafe_allow_html=True)
    else:
        st.markdown(f"""
        <div class="message bot-message">
            <div class="message-content">
                {content}
                <div class="message-time">{timestamp}</div>
            </div>
        </div>
        """, unsafe_allow_html=True)

# 加载指示器
if st.session_state.loading:
    st.markdown("""
    <div class="loading-indicator">
        <div class="loading-spinner"></div>
        <span>AI正在思考中...</span>
    </div>
    """, unsafe_allow_html=True)

st.markdown('</div>', unsafe_allow_html=True)  # 关闭聊天历史区域

# 推荐问题区域
if st.session_state.recommended_questions and not st.session_state.loading:
    st.markdown("""
    <div style='padding: 0 1.5rem 0.5rem;'>
        <h4 style='margin-bottom: 0.5rem; color: #6c757d; font-size: 0.95rem;'>💡 推荐问题：</h4>
    </div>
    """, unsafe_allow_html=True)
    
    cols = st.columns(1) if len(st.session_state.recommended_questions) <= 1 else st.columns(2)
    for i, question in enumerate(st.session_state.recommended_questions):
        col_idx = i % len(cols)
        if cols[col_idx].button(question, use_container_width=True, key=f"recommended_{i}"):
            st.session_state.selected_question = question
            st.session_state.user_input = question
            send_message()

# 输入区域
st.markdown('<div class="input-container">', unsafe_allow_html=True)

# 用户输入
user_input = st.text_area(
    "",
    placeholder="请输入您的问题...",
    label_visibility="collapsed",
    key="user_input",
    height=100
)

# 发送按钮
send_button = st.button("发送消息", use_container_width=True, type="primary", key="send_button")

# 当发送按钮被点击时
if send_button and user_input and user_input.strip():
    send_message()

# 显示使用提示
st.markdown("""
<div class="info-card" style="margin-top: 1.5rem; background-color: #f8f9fa; padding: 1rem; border-radius: 8px; border-left: 4px solid #4a6fa5;">
    <h4>📋 使用说明</h4>
    <ul>
        <li>1. 请在左侧边栏设置您的通义千问API密钥</li>
        <li>2. 在输入框中输入您的问题</li>
        <li>3. 点击发送按钮获取AI回复</li>
        <li>4. 可以在左侧边栏清除聊天记录重新开始</li>
        <li>5. 系统将自动生成后续推荐问题</li>
        <li>6. API密钥仅保存在当前会话中，不会被持久化存储</li>
    </ul>
</div>
""", unsafe_allow_html=True)

# 页脚
st.markdown("""
---
<div style='text-align: center; color: var(--secondary-color); font-size: 0.9rem; margin-top: 2rem;'>
    © 2024 LangChain智能聊天机器人 | 基于LangChain和通义千问API
</div>
""", unsafe_allow_html=True)

st.markdown('</div>', unsafe_allow_html=True)  # 关闭输入容器
st.markdown('</div>', unsafe_allow_html=True)  # 关闭聊天容器
st.markdown('</div>', unsafe_allow_html=True)  # 关闭主容器